;; function to test melpa mirrors speed
;; via: emacs-china.org/t/elpa/18226 by twlz0ne
(when (or (eq system-type 'gnu/linux)
          (executable-find "curl"))
  (defun con5-find-fastest-elpa-mirror ()
    "Find the fatest mirror for me.

Inspied by @xuchunyang https://emacs-china.org/t/elpa/11192/9"
    (interactive)
    (require 'request)
    (with-output-to-temp-buffer "*Elpa mirror test*"
      (princ "  score (s)  mirror                        last updated\n")
      (princ "-----------  ----------------------------  ------------------\n"))
    (dolist (mirror package-mirror-alist)
      (let ((url (cdr (assoc "melpa" mirror)))
            (begin-time (float-time (current-time)))
            (request-backend (car '(curl url-retrieve))))
        (request (concat url "archive-contents")
                 :timeout 30
                 :complete
                 (cl-function
                  (lambda (&key response symbol-status &allow-other-keys)
                    (with-current-buffer "*Elpa mirror test*"
                      (goto-char (point-max))
                      (let ((inhibit-read-only t))
                        (insert (format "%11s  %-29s [%s]\n"
                                        (if (eq symbol-status 'success)
                                            (format
                                             "%6fs"
                                             (- (float-time (current-time)) begin-time))
                                          symbol-status)
                                        (url-host (url-generic-parse-url url))
                                        (if (eq symbol-status 'success)
                                            (request-response-header response "Last-Modified")))))))))))))

;; -------- where the current file is --------
;; via: octolinker-demo.now.sh/MatthewZMD/.emacs.d#company-tabnine
(defun p1uxtar-get-current-directory ()
  "Display dired/file-name when visiting a file.
Otherwise the function displays `buffer-name'."
  (interactive)
  (let ((dir-file (buffer-file-name)))
    (if dir-file
        (message dir-file)
      (message (buffer-name)))))

;; -------- open-file-at-cursor --------

(defvar xah-open-file-at-cursor-pre-hook nil "Hook for `xah-open-file-at-cursor'.
Functions in the hook is called in order, each given the raw input text (path) as arg.
The first return non-nil, its value is given to `xah-open-file-at-cursor' as input. rest functions in hook is ignored.
This is useful for transforming certain url into file path. e.g. change
http://xahlee.info/emacs/index.html
to
C:/Users/xah/web/xahlee_info/emacs/index.html
, so instead of opening in browser, it opens in emacs as file.")

(defun con5-open-file-at-cursor ()
  "Open the file path under cursor.

• If there is selection, use it for path.
• Path can be {relative, full path, URL}.
• If the path starts with 「https*://」, open the URL in browser.
• Path may have a trailing 「:‹n›」 that indicates line number, or 「:‹n›:‹m›」 with line and column number. If so, jump to that line number.

If path does not have a file extension, automatically try with .el for elisp files.

See also `xah-open-file-at-cursor-pre-hook'.

This command is similar to `find-file-at-point' but without prompting for confirmation.

URL `http://xahlee.info/emacs/emacs/emacs_open_file_path_fast.html'
Created: 2020-10-17
Version: 2024-05-20"
  (interactive)
  (let (xinput xinput2 xpath)
    (setq xinput (if (region-active-p)
                     (buffer-substring-no-properties (region-beginning) (region-end))
                   (let ((xp0 (point)) xp1 xp2
                         (xpathStops "^  \t\n\"`'‘’“”|()[]{}「」<>〔〕〈〉《》【】〖〗«»‹›❮❯❬❭〘〙·。\\"))
                     (skip-chars-backward xpathStops)
                     (setq xp1 (point))
                     (goto-char xp0)
                     (skip-chars-forward xpathStops)
                     (setq xp2 (point))
                     (goto-char xp0)
                     (buffer-substring-no-properties xp1 xp2))))
    (setq xinput2 (if (> (length xah-open-file-at-cursor-pre-hook) 0)
                      (let ((xprehook (run-hook-with-args-until-success 'xah-open-file-at-cursor-pre-hook xinput)))
                        (if xprehook xprehook xinput))
                    xinput))

    (setq xpath
          (cond
           ((string-match "^file:///[A-Za-z]:/" xinput2) (substring xinput2 8))
           ((string-match "^file://[A-Za-z]:/" xinput2) (substring xinput2 7))
           (t xinput2)))

    (if (string-match-p "\\`https?://" xpath)
        (browse-url xpath)
      (let ((xpathNoQ
             (let ((xHasQuery (string-match "\?[a-z]+=" xpath)))
               (if xHasQuery
                   (substring xpath 0 xHasQuery)
                 xpath))))
        (cond
         ((string-match "#" xpathNoQ)
          (let ((xfpath (substring xpathNoQ 0 (match-beginning 0)))
                (xfractPart (substring xpathNoQ (1+ (match-beginning 0)))))
            (if (file-exists-p xfpath)
                (progn
                  (find-file xfpath)
                  (goto-char (point-min))
                  (search-forward xfractPart))
              (progn
                (message "File does not exist. Created at\n%s" xfpath)
                (find-file xfpath)))))
         ((string-match "^\\`\\(.+?\\):\\([0-9]+\\)\\(:[0-9]+\\)?\\'" xpathNoQ)
          (let ((xfpath (match-string-no-properties 1 xpathNoQ))
                (xlineNum (string-to-number (match-string-no-properties 2 xpathNoQ))))
            (if (file-exists-p xfpath)
                (progn
                  (find-file xfpath)
                  (goto-char (point-min))
                  (forward-line (1- xlineNum)))
              (progn
                (message "File does not exist. Created at\n%s" xfpath)
                (find-file xfpath)))))
         ((file-exists-p xpathNoQ)
          (progn ; open f.ts instead of f.js
            (let ((xext (file-name-extension xpathNoQ))
                  (xfnamecore (file-name-sans-extension xpathNoQ)))
              (if (and (string-equal xext "js")
                       (file-exists-p (concat xfnamecore ".ts")))
                  (progn
                    (find-file (concat xfnamecore ".ts"))
                    (warn "Typescript file .ts exist, opening it"))

                (find-file xpathNoQ)))))
         ((file-exists-p (concat xpathNoQ ".el"))
          (find-file (concat xpathNoQ ".el")))
         (t (progn
              (message "File does not exist. Created at\n%s" xpathNoQ)
              (find-file xpathNoQ))))))))

(global-set-key (kbd "C-c C-f") 'con5-open-file-at-cursor)

;; Delete Enclosed Text by Xah
;; ergoemacs.org/emacs/elisp_examples.html
(defun con5-delete-enclosed-text ()
  "Delete texts between any pair of delimiters."
  (interactive)
  (save-excursion
    (let (p1 p2)
      (skip-chars-backward "^([<>“\"")
      (setq p1 (point))
      (skip-chars-forward "^)]<>”\"")
      (setq p2 (point))
      (delete-region p1 p2))))
(global-set-key (kbd "C-M-k") 'con5-delete-enclosed-text)

;; via Ladicle's Emacs Configuration
;; ladicle.com/post/config/
(defun p1uxtar-kill-word-at-point ()
  "Smart kill word or region."
  (interactive)
  (let ((char (char-to-string (char-after (point)))))
    (cond
     ((string= " " char)
      (delete-horizontal-space))
     ((string-match "[\t\n -@\[-`{-~],.、。" char)
      (kill-word 1))
     (t
      (forward-char)
      (backward-word)
      (kill-word 1)))))
(global-set-key (kbd "M-d")  'p1uxtar-kill-word-at-point)

;; -------- refresh current buffer --------
(defun revert-current-buffer ()
  "Revert the current buffer."
  (interactive)
  (message "Revert this buffer")
  (text-scale-set 0)
  (widen)
  (revert-buffer t t))

(global-set-key (kbd "<f5>") #'revert-current-buffer)


(defun con5-select-text-in-quote ()
  "Select text between the nearest left and right delimiters.
Delimiters here includes the following chars: \"`<>(){}[]“”‘’‹›«»「」『』【】〖〗《》〈〉〔〕（）
This command select between any bracket chars, does not consider nesting. For example, if text is
(a(b)c▮)
the selected char is “c”, not “a(b)c”.

URL `http://xahlee.info/emacs/emacs/modernization_mark-word.html'
Version 2020-11-24 2021-07-11"
  (interactive)
  (let ( $skipChars $p1 )
    (setq $skipChars "^\"`<>(){}[]“”‘’‹›«»「」『』【】〖〗《》〈〉〔〕（）〘〙")
    (skip-chars-backward $skipChars)
    (setq $p1 (point))
    (skip-chars-forward $skipChars)
    (set-mark $p1)))

(global-set-key (kbd "M-'") 'con5-select-text-in-quote)

(defun p1uxtar-repeat ()
  "Repeat last command."
  (interactive)
  (eval (car command-history)))
